#include "ls_p2p_client.h"
#include "ls_common.h"
#include "ls_list.h"
#include "lwip/sockets.h"
#include "PPCS_API.h"
#include "cJSON.h"

#define DBG_TAG "P2P"
#include "ls_trace_common.h"


typedef enum
{
   LS_P2P_SESSION_CMD = 0,
   LS_P2P_CHANNEL_VIDEO,
   LS_CUSTOM_CHANNEL,
   LS_P2P_CHANNEL_MAX,
} LS_P2P_SESSION_E;

/// @brief
typedef struct LS_P2P_SESSION_S
{
   bool isActive;
   ls_list_head list;

   pthread_t recv_tid;

   bool run;
   uint32_t sessionId;
   LS_P2P_SESSION_E type;
   uint8_t refcnt;
} P2P_SESSION_S;

/// @brief
typedef struct ls_p2p_client
{
   bool inited;
   pthread_t listen_tid;
   pthread_t keeplive_tid;
   bool listen_run;
   ls_list_head sessionManger;
   pthread_mutex_t mutex;
   uint8_t sessionCnt;

   sem_t    keeplive_sem;
} p2p_client;

/// @brief
static p2p_client gstP2PObj = {
    .inited = false,
    .listen_tid = NULL,
    .listen_run = 0,
    .sessionCnt = 0,
};




#define P2P_VIDEO_CHANNEL_PKG_SIZE 1024
#define WRITE_THRESHOLD            (131072)  // 128K



// #define P2P_TEST_DEVICE_ID                "OEMAAAF-000000-NXYYM"
// #define P2P_TEST_API_LICENCE              "DDRILV:EasyView"
// #define P2PInistr                         "EFGBFFBJKEJKGGJJEEGFFHELHHNNHONHGLFNBHCCAEJDLNLPDDAGCIOFGDLGJMLAAOMOKCDLOONOBICJJIMM:cs2p2p"



#define P2P_TEST_DEVICE_ID                   "SOLARA-000000-JEEMM"
#define P2P_TEST_API_LICENCE                 "ECUSNZ:SolarCom"
#define P2PInistr                            "EBGDEIBIKEJOGCJNEJGKFIEDHDNJBLLBGPEFBGGEADMJLGPOCKEHDJKIGNKAMNKIAAJHLKHNLDPNDLGJNOIIJNFEMGKFADHBBCHECLEIJPOABBCPFGEHKCIE:SolarCom"

#define WAKEUP_KEY "Solar_Xiamen.Com"


// #define WAKEUP_SVR_PORT1                     12306
// #define WAKEUP_SVR_IP1                       "192.168.6.105"

#define WAKEUP_SVR_PORT1                     12306
#define WAKEUP_SVR_IP1                       "121.40.107.54"

#define WAKEUP_SVR_PORT2                     12306
#define WAKEUP_SVR_IP2                       "43.128.71.64"

#define WAKEUP_SVR_PORT3                     12306
#define WAKEUP_SVR_IP3                       "49.51.188.218"


static p2p_recvOnlisten       grecvOnlisten = NULL;
static p2p_OnConnectStatus    gOnConnectStatus=NULL;



static void *__ls_p2p_session_send_pro(void *param);
static void *__ls_p2p_session_recv_pro(void *param);

static P2P_SESSION_S *__LS_P2P_FindSession(uint32_t _SessionId);
static int32_t __LS_P2P_FreeSession(uint32_t _SessionId);

/// @brief
/// @param type
/// @param _SessionId
/// @return
static P2P_SESSION_S *__LS_P2P_AllocSession(LS_P2P_SESSION_E type, uint32_t _SessionId)
{
   P2P_SESSION_S *sessionInfo = NULL;
   //  = __LS_P2P_FindSession(_SessionId);
   // if(sessionInfo)
   //    return sessionInfo;
   pthread_mutex_lock(&gstP2PObj.mutex);
   LS_GOTO(gstP2PObj.sessionCnt < 1, sessionInfo, NULL, LS_P2P_AllocSession_ERROR, "SessionCnt is MAX !!!!!!!!!!!!!!!!!!!!");

   sessionInfo = malloc(sizeof(P2P_SESSION_S));
   LS_GOTO(sessionInfo != NULL, sessionInfo, NULL, LS_P2P_AllocSession_ERROR, "ls malloc failed!");
   bzero(sessionInfo, sizeof(P2P_SESSION_S));

   sessionInfo->isActive = 1;
   sessionInfo->type = type;
   sessionInfo->refcnt++;
   sessionInfo->sessionId = _SessionId;
   
   list_add_tail(&sessionInfo->list, &gstP2PObj.sessionManger);

   gstP2PObj.sessionCnt++;
   LS_TRACE_INFO("malloc session id:%d", sessionInfo->sessionId);

LS_P2P_AllocSession_ERROR:
   pthread_mutex_unlock(&gstP2PObj.mutex);
   return sessionInfo;
}

/// @brief 释放一个Session
/// @param _SessionId
/// @return
static int32_t __LS_P2P_FreeSession(uint32_t _SessionId)
{
   int sRet32 = -1;
   pthread_mutex_lock(&gstP2PObj.mutex);
   LS_GOTO(gstP2PObj.sessionCnt > 0, sRet32, -1, LS_P2P_FreeSession_ERROR, "SessionCnt is MAX !!!!!!!!!!!!!!!!!!!!");

   P2P_SESSION_S *Item;
   list_for_each_entry(Item, &gstP2PObj.sessionManger, list)
   {
      if (Item->sessionId ==  _SessionId)
      {
         Item->refcnt--;
         sRet32 = Item->type;
         //LS_TRACE_INFO("Item->refcnt:%d", Item->refcnt);
         if (!Item->refcnt)
         {
            list_del(&Item->list);
            LS_TRACE_INFO("free session id:%d ", Item->sessionId);
            ls_free(Item);
            gstP2PObj.sessionCnt--;
         }

         break;
      }
   }

LS_P2P_FreeSession_ERROR:
   if (sRet32 == -1)
      LS_TRACE_ERROR("not find session:%s", _SessionId);
   pthread_mutex_unlock(&gstP2PObj.mutex);
   return sRet32;
}

/// @brief 返回一个session
/// @param _SessionId
/// @return
P2P_SESSION_S *__LS_P2P_FindSession(uint32_t _SessionId)
{
   P2P_SESSION_S *Item = NULL;
   int s32Ret = -1;
   pthread_mutex_lock(&gstP2PObj.mutex);
   LS_GOTO(gstP2PObj.sessionCnt > 0, Item, NULL, LS_P2P_FindSession_ERROR, "SessionCnt is 0 !!!!!!!!!!!!!!!!!!!!");

   list_for_each_entry(Item, &gstP2PObj.sessionManger, list)
   {
      if (Item->sessionId ==  _SessionId || _SessionId == -1)
      {
         // LS_TRACE_DEBUG("find session id:%d", Item->sessionId);
         Item->refcnt++;
         s32Ret = 0;
         break;
      }
   }
LS_P2P_FindSession_ERROR:
   if (s32Ret == -1)
      LS_TRACE_ERROR("not find session:%d", _SessionId);
   pthread_mutex_unlock(&gstP2PObj.mutex);
   return Item;
}


///
int32_t __LS_P2P_SessionEmpty()
{
   pthread_mutex_lock(&gstP2PObj.mutex);
   int ret = list_empty(&gstP2PObj.sessionManger);
   pthread_mutex_unlock(&gstP2PObj.mutex);
   return ret;
}



char *GetRandomString(char *output_String, int Len)
{
   srand((unsigned long)time(NULL));

   for (int i = 0; i < Len; i++)
   {
      switch (abs(rand() % 5))
      {
      case 0:
         output_String[i] = 'A' + rand() % 26;
         break;

      case 1:
         output_String[i] = 'a' + rand() % 26;
         break;

      case 2:
         output_String[i] = '0' + rand() % 10;
         break;

      case 3:
         output_String[i] = 'A' + rand() % 26;
         break;

      case 4:
         output_String[i] = '0' + rand() % 10;
         break;

      default:
         output_String[i] = 'A' + rand() % 26;
         break;
      }
   }

   return output_String;
}

/// @brief 
/// @param keystr 
/// @param src 
/// @param dest 
/// @param maxsize 
/// @return 
int iPN_StringEnc(const char *keystr, const char *src, char *dest, unsigned int maxsize)
{
   int Key[17] = {0};
   unsigned int i;
   unsigned int s, v;

   if (maxsize < strlen(src) * 2 + 3)
   {
      return -1;
   }

   for (i = 0; i < 16; i++)
   {
      Key[i] = keystr[i];
   }

   srand((unsigned int)time(NULL));
   s = abs(rand() % 256);
   memset(dest, 0, maxsize);
   dest[0] = 'A' + ((s & 0xF0) >> 4);
   dest[1] = 'a' + (s & 0x0F);

   for (i = 0; i < strlen(src); i++)
   {
      v = s ^ Key[(i + s * (s % 23)) % 16] ^ src[i];
      dest[2 * i + 2] = 'A' + ((v & 0xF0) >> 4);
      dest[2 * i + 3] = 'a' + (v & 0x0F);
      s = v;
   }

   return 0;
}


/// @brief 
/// @param keystr 
/// @param src 
/// @param dest 
/// @param maxsize 
/// @return 
int iPN_StringDnc(const char *keystr, const char *src, char *dest, unsigned int maxsize) {
    int Key[17] = {0};
    unsigned int i;
    unsigned int s, v;

    if ((maxsize < strlen(src) / 2) || (strlen(src) % 2 == 1))
    {
        return -1;
    }

    for (i = 0 ; i < 16; i++)
    {
        Key[i] = keystr[i];
    }

    memset(dest, 0, maxsize);
    s = ((src[0] - 'A') << 4) + (src[1] - 'a');

    for (i = 0; i < strlen(src) / 2 - 1; i++)
    {
        v = ((src[i * 2 + 2] - 'A') << 4) + (src[i * 2 + 3] - 'a');
        dest[i] = v ^ Key[(i + s * (s % 23)) % 16] ^ s;

        if (dest[i] > 127 || dest[i] < 32)
        {
            return -1; // not a valid character string
        }

        s = v;
    }

    return 0;
}



/// @brief
/// @param p
/// @return
static ATTR_NOINIT_PSRAM_SECTION CHAR recv_buf[P2P_VIDEO_CHANNEL_PKG_SIZE];

static void *__ls_p2p_session_recv_pro(void *param)
{
   int sessionID = (int)param;
   LS_TRACE_DEBUG("session %u  recv start!", sessionID);

   P2P_SESSION_S *sessionInfo = __LS_P2P_FindSession(sessionID);

   int8_t readChannel;
   uint8_t checkChannel = 0;
   UINT32 ReadSize;
   int ret;
   
   while (sessionInfo->run)
   {
      readChannel = -1;
      //
      ret = PPCS_Check_Buffer(sessionID,checkChannel,NULL,&ReadSize);
      if ((ret == ERROR_PPCS_SUCCESSFUL && ReadSize > 0) || ret == ERROR_PPCS_SESSION_CLOSED_REMOTE)
      {
         readChannel = checkChannel;
      }


      checkChannel++;
      if(!(checkChannel < P2P_CHANNEL_MAX))checkChannel=0;
            
      if(readChannel != -1)
      {
         //LS_TRACE_ERROR("sessionID:%d %d read:%d %d ",sessionID,sessionInfo->sessionId,readChannel,ReadSize);
         ReadSize = ReadSize > P2P_VIDEO_CHANNEL_PKG_SIZE ? P2P_VIDEO_CHANNEL_PKG_SIZE:ReadSize;
         ret = PPCS_Read(sessionID,readChannel, recv_buf, &ReadSize, 0xFFFFFFFF);
         if (ret == ERROR_PPCS_SUCCESSFUL)
         {
            if(grecvOnlisten)grecvOnlisten(readChannel,recv_buf,ReadSize);
         }
         else
         {
            gOnConnectStatus(0);
            LS_TRACE_DEBUG("session close:%d",ret);
            sem_post(&gstP2PObj.keeplive_sem);
            sessionInfo->isActive = 0;
            break;
         }
      }

      usleep(20);
   }
   __LS_P2P_FreeSession(sessionID);
   LS_TRACE_DEBUG("session %u  recv end!", sessionID);
   return NULL;
}



static char DWK[17]={0};          // 每次登陆服务器之前生成的一串随机字符串
static char DWK_ENC[40]={0};      // 经过加密后的DWK


static char DID_DWK[50]={0};      // DID@DWK
static char DID_DWK_ENC[100]={0}; // 经过WakeupKey加密的DID@DWK


static char RCV_DWK[17]={0};
/// @brief
/// @param p
/// @return
static void *__ls_p2p_client_keeplive_pro(void *param)
{
   p2p_client *Obj = (p2p_client *)&gstP2PObj;
   LS_TRACE_DEBUG("p2p keeplive start!");
   int err_cnt = 0;
   int nc;
   int sockId = -1;
GOTO_P2P_CLIENT_REWHILE:
   
   nc = P2P_TEST_DEVICE_ID[strlen(P2P_TEST_DEVICE_ID) - 1] % 3;
   sockId = 0;
   while (Obj->listen_run)
   {
      //start 
      err_cnt = 0;
      LS_TRACE_DEBUG("p2p wakeup start!");
      memset(DWK, 0, sizeof(DWK));
      snprintf(DID_DWK, sizeof(DID_DWK), "%s@%s", P2P_TEST_DEVICE_ID, GetRandomString(DWK, sizeof(DWK) - 1));
      

      iPN_StringEnc(WAKEUP_KEY, DID_DWK, DID_DWK_ENC, sizeof(DID_DWK_ENC)); // login pkt
      LS_TRACE_DEBUG("DID_DWK:%s", DID_DWK);


      nc = (nc + 1) % 3;
      struct sockaddr_in http_sockaddr;
      /* 1、登陆服务器 ：DID@DWK->wakeupkey加密->DID_DWK_ENC,发送DID_DWK_ENC到唤醒服务器 */
      http_sockaddr.sin_family = AF_INET;
      switch (nc)// KW    switch (wificonfig.heartbeat_server)
      {
         case 1:
            http_sockaddr.sin_port = htons(WAKEUP_SVR_PORT1);
            http_sockaddr.sin_addr.s_addr = inet_addr(WAKEUP_SVR_IP1);
            break;
         case 2:
            http_sockaddr.sin_port = htons(WAKEUP_SVR_PORT2);
            http_sockaddr.sin_addr.s_addr = inet_addr(WAKEUP_SVR_IP2);
            break;
         case 3:
            http_sockaddr.sin_port = htons(WAKEUP_SVR_PORT3);
            http_sockaddr.sin_addr.s_addr = inet_addr(WAKEUP_SVR_IP3);
            break;
         default:
            http_sockaddr.sin_port = htons(WAKEUP_SVR_PORT1);
            http_sockaddr.sin_addr.s_addr = inet_addr(WAKEUP_SVR_IP1);
            break;
      }

      // create socket.
      int ret = socket(AF_INET, SOCK_STREAM, 0);
      if (ret < 0)
      {
         LS_TRACE_ERROR("create socket error:%d!", ret);
         sleep(1);
         continue;
      }
      sockId = ret;
      /* 2、心跳包 ：DWK->wakeupkey加密->DWK_ENC,发送DWK_ENC到唤醒服务器维持心跳 */

      ret = connect(sockId, (struct sockaddr *)&http_sockaddr, sizeof(struct sockaddr));
      if (ret < 0)
      {
         LS_TRACE_INFO("connect socket error:%d!", ret);
         closesocket(sockId);
         sleep(1);
         continue;
      }

      //登录
      
      send(sockId, DID_DWK_ENC, strlen(DID_DWK_ENC), 0);
     
      //心跳
      GetRandomString(DWK, sizeof(DWK) - 1);
      memset(DWK_ENC, 0, sizeof(DWK_ENC));
      iPN_StringEnc(WAKEUP_KEY, DWK, DWK_ENC, sizeof(DWK_ENC));// keep alive pkt

      int send_len = strlen(DWK_ENC);
      send(sockId, DWK_ENC,send_len, 0);
      // send a heartbeat pkt
      
      
      fd_set  readfds;
      /* 2、心跳包 ：DWK->wakeupkey加密->DWK_ENC,发送DWK_ENC到唤醒服务器维持心跳 */
      while (Obj->listen_run)
      {
        FD_ZERO(&readfds);
        FD_SET(sockId, &readfds);
        struct timeval timeout={50,0};

         ret = lwip_select(sockId+1,&readfds,NULL,NULL,&timeout);
         if(ret == 0)
         {
            //发送心跳
            ret = send(sockId, DWK_ENC,send_len, 0);
            if(ret == send_len){
               err_cnt =0;
               LS_TRACE_DEBUG("p2p heartbeat success!");
            }
            else{
               LS_TRACE_ERROR("p2p heartbeat failed!");
               err_cnt ++;
               sleep(err_cnt);
               if(err_cnt > 6)
               {
                  break;
               }
            }
             
         }
         else if(ret < 0)
         {
            LS_TRACE_ERROR("select error failed!");   
            closesocket(sockId);
            sleep(1);
            break;
         }
         else
         {
               memset(RCV_DWK, 0, sizeof(RCV_DWK));
               int bytes_rece = recv(sockId, RCV_DWK, sizeof(RCV_DWK) - 1, 0);
               if((bytes_rece == sizeof(RCV_DWK) - 1 && !strncmp(DWK, RCV_DWK,sizeof(RCV_DWK) - 1))
                  ||
                  (RCV_DWK[0] == 0x98 && RCV_DWK[1] == 0x3b &&
                   RCV_DWK[2] == 0x16 && RCV_DWK[3] == 0xf8 &&
                   RCV_DWK[4] == 0xf3 && RCV_DWK[5] == 0x9c))
               {
                  //收到正确得数据包被唤醒了
                  closesocket(sockId);
                  goto GOTO_P2P_LISTEN;
               }
               else if(bytes_rece == 0)
               {
                  LS_TRACE_INFO("heartbeat close");
                  closesocket(sockId);
                  sleep(10);
                  goto GOTO_P2P_CLIENT_REWHILE;
               }
               else
               {
                  LS_TRACE_DEBUG("bytes_rece:%d RCV_DWK:%s",bytes_rece,RCV_DWK);
                  err_cnt ++;
                  if(err_cnt > 6)
                  {
                     closesocket(sockId);
                     break;
                  }
               }
         }
      }//while()2
   }//while()1

   int ret;
GOTO_P2P_LISTEN:
    
   ret = PPCS_Listen(P2P_TEST_DEVICE_ID,60, 0,1, P2P_TEST_API_LICENCE);
   if (ret >= 0)
   {
         int sessionID = ret;
         LS_TRACE_DEBUG("client session id is:%d", ret);
         P2P_SESSION_S *session = __LS_P2P_AllocSession(LS_P2P_SESSION_CMD, sessionID);
         if (session != NULL)
         {
            session->run = 1;
            pthread_create(&session->recv_tid, NULL, __ls_p2p_session_recv_pro, (void *)sessionID);
            // 发送数据给SPI
         }
         else
         {
            uint32_t is_busy = 1;
            PPCS_Write(sessionID, LS_P2P_SESSION_CMD,(CHAR *)&is_busy, sizeof(is_busy));
            PPCS_Close(sessionID);
         }
   }

   sleep(1);
   if(Obj->listen_run)
   {
      
      sem_wait(&gstP2PObj.keeplive_sem);
      LS_TRACE_DEBUG("p2p keeplive restart!");
      goto GOTO_P2P_CLIENT_REWHILE;
   }
   

   LS_TRACE_DEBUG("p2p keeplive end!");
   return NULL;
}


#if 1
/// @brief
/// @param param
static void __ls_p2p_client_listen_pro(void *param)
{
   p2p_client *Obj = (p2p_client *)param;

  
   const char *MyID = P2P_TEST_DEVICE_ID;
    LS_TRACE_DEBUG("p2p listen start:%s---%s!",MyID,P2P_TEST_API_LICENCE);
   while (Obj->listen_run)
   {
      int ret = __LS_P2P_SessionEmpty();
      // 监听
      if(ret)
      {
         // LS_TRACE_DEBUG("PPCS_Listen ");
         ret = PPCS_Listen(MyID,86400, 0,1,P2P_TEST_API_LICENCE);
      }
      else
      {
         // LS_TRACE_DEBUG("PPCS_Listen break:%d",ret);
         sleep(1);
         continue;
      }
       
      if (ret >= 0)
      {
         int sessionID = ret;
         LS_TRACE_DEBUG("client session id is:%d", ret);
         P2P_SESSION_S *session = __LS_P2P_AllocSession(LS_P2P_SESSION_CMD, sessionID);
         if (session != NULL)
         {
            gOnConnectStatus(1);
            session->run = 1;
            pthread_create(&session->recv_tid, NULL, __ls_p2p_session_recv_pro, (void *)sessionID);
            // 发送数据给SPI

         }
         else
         {
            uint32_t is_busy = 1;
            PPCS_Write(sessionID, LS_P2P_SESSION_CMD,(CHAR *)&is_busy, sizeof(is_busy));
            PPCS_Close(sessionID);
         }
      }
      else
      {

         sleep(3);
         LS_TRACE_ERROR("error code is:%d", ret);
      }

 
      usleep(100000);
   }
   LS_TRACE_DEBUG("p2p listen end!");
}
#endif 

static  void TimerCallback( TimerHandle_t xTimer )
{
   st_PPCS_Session SInfo;
   // 检测是否close
   P2P_SESSION_S *Item;

   list_for_each_entry(Item, &gstP2PObj.sessionManger,list)
   {
      if(!Item->isActive)
      {
         Item->run  = 0;
         pthread_join(Item->recv_tid,NULL);
         PPCS_Close(Item->sessionId);
         __LS_P2P_FreeSession(Item->sessionId);
         break;
      }

      INT32 ret = PPCS_Check(Item->sessionId,&SInfo);
      if (ret == ERROR_PPCS_SESSION_CLOSED_REMOTE)
      {
         gOnConnectStatus(0);
         LS_TRACE_DEBUG("session close");
         sem_post(&gstP2PObj.keeplive_sem);
         Item->isActive = 0;    
      }

      // LS_TRACE_DEBUG("SInfo.Skt:%d",SInfo.Skt);
      // LS_TRACE_DEBUG("SInfo.ConnectTime:%u",SInfo.ConnectTime);
      // LS_TRACE_DEBUG("ret:%d",ret);
   }

   // cJSON *root = cJSON_Parse(PPCS_GetAPIInformation());
   // if(root)
   // {
   //    cJSON *LastLoginAck=cJSON_GetObjectItem(root,"LastLoginAck");
   //    LS_TRACE_DEBUG("LastLoginAck:%d",LastLoginAck->valueint);
   //    cJSON_Delete(root);  
   // }
}


/// @brief 
/// @param l 
/// @return 
int ls_p2p_client_init(p2p_recvOnlisten lr,p2p_OnConnectStatus ls)
{
   if(gstP2PObj.inited == true) return ;
   grecvOnlisten     = lr;
   gOnConnectStatus  = ls;

   LS_TRACE_DEBUG("APIInformation:%s\r\n", PPCS_GetAPIInformation());

   int  MaxNumSess = 1; // Max Number Session: 1~256.
   int  SessAliveSec = 10; // session timeout close alive: 6~30.
   char InitJsonString[256] = {};
   snprintf(InitJsonString, sizeof(InitJsonString), "{\"InitString\":\"%s\",\"MaxNumSess\":%d,\"SessAliveSec\":%d}",P2PInistr, MaxNumSess, SessAliveSec);

   int ret = PPCS_Initialize(InitJsonString);
   LS_RETURN(ret == ERROR_PPCS_SUCCESSFUL, -1, "PPCS_Initialize failed!");


   st_PPCS_NetInfo param;
   PPCS_NetworkDetect(&param,0);
   LS_TRACE_DEBUG("bFlagInternet:%d",param.bFlagInternet);
   LS_TRACE_DEBUG("bFlagHostResolved:%d",param.bFlagHostResolved);
   LS_TRACE_DEBUG("bFlagServerHello:%d",param.bFlagServerHello);
   LS_TRACE_DEBUG("NAT_Type:%d",param.NAT_Type);
   LS_TRACE_DEBUG("MyLanIP:%s",param.MyLanIP);
   LS_TRACE_DEBUG("MyWanIP:%s",param.MyWanIP);
   INIT_LIST_HEAD(&gstP2PObj.sessionManger);

   pthread_mutex_init(&gstP2PObj.mutex, NULL);

   sem_init(&gstP2PObj.keeplive_sem,0,0);

   // 默认最小值
   gstP2PObj.listen_run = 1;
   pthread_attr_t attr;
   uint32_t stacksize = 0x8000;
   pthread_attr_init(&attr); /*初始化线程属性*/
   pthread_attr_setstacksize(&attr, stacksize);
   // pthread_create(&gstP2PObj.listen_tid, NULL, __ls_p2p_client_listen_pro, &gstP2PObj);
   pthread_create(&gstP2PObj.keeplive_tid,NULL, __ls_p2p_client_keeplive_pro, &gstP2PObj);
   pthread_attr_destroy(&attr);    

   TimerHandle_t timeId = xTimerCreate("p2p client",1000,pdTRUE,(void*)1,TimerCallback);
   xTimerStart(timeId,1000);

   gstP2PObj.inited = true;
   return 0;
}



/// @brief 进入休眠模式
/// @return 
int ls_p2p_client_into_sleep()
{
   if(gstP2PObj.inited != true) return ;
   if(list_empty(&gstP2PObj.sessionManger)) return 0;

   P2P_SESSION_S *Item = __LS_P2P_FindSession(-1);

   Item->isActive = 0;

   __LS_P2P_FreeSession(Item->sessionId);

   sem_post(&gstP2PObj.keeplive_sem);
   return 0;
}


/// @brief 发送数据
/// @return 
int ls_p2p_client_send_data(P2P_CHANNEL_E channel,const char *data,uint32_t datalen)
{
   if(gstP2PObj.inited != true) return ;
   if(list_empty(&gstP2PObj.sessionManger))return -1;
   P2P_SESSION_S *Item = __LS_P2P_FindSession(-1);

   int ret = PPCS_Write(Item->sessionId,channel,data,datalen);
   if(ret == ERROR_PPCS_SESSION_CLOSED_REMOTE)
   {

   }
   __LS_P2P_FreeSession(Item->sessionId);

   return ret;
}


/// @brief 发送数据
/// @return 
int ls_p2p_client_send_data_udp(P2P_CHANNEL_E channel,const char *data,uint32_t datalen)
{
   if(gstP2PObj.inited != true) return ;
   if(list_empty(&gstP2PObj.sessionManger))return -1;
   P2P_SESSION_S *Item = __LS_P2P_FindSession(-1);

   if(P2P_CHANNEL_VIDEO == channel || P2P_CHANNEL_CMD == channel)
   {
      memcpy((char *)data+3,"SOLAR000000",11);
   }

   int send_data = datalen;
   int send_offset = 0;
   // LS_TRACE_DEBUG("channel:%d",channel);
   int ret;
   uint32_t WriteSize = 0;
   uint32_t ReadSize = 0;
   while(datalen)
   {
      send_data = datalen > 1024 ? 1024:datalen;


      ret = PPCS_Check_Buffer(Item->sessionId,channel,&WriteSize,&ReadSize);
      if (WriteSize > WRITE_THRESHOLD && ret == ERROR_PPCS_SUCCESSFUL)
      {
         LS_TRACE_ERROR("write buff is long:%d  %d %d!!!!",WriteSize,ret,Item->sessionId);
         sleep(1);
         continue;
      }

      ret = PPCS_Write(Item->sessionId,channel,data+send_offset,send_data);
      if (ERROR_PPCS_SESSION_CLOSED_REMOTE == ret)
      {
         gOnConnectStatus(0);
         LS_TRACE_DEBUG("session close");
         sem_post(&gstP2PObj.keeplive_sem);
         Item->isActive = 0;    
         LS_TRACE_DEBUG("error:%d",ret);
      }

      datalen -= send_data;
      send_offset+= send_data;
   }

   __LS_P2P_FreeSession(Item->sessionId);


   return send_offset;
}



